package com.donglan.pethome.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.donglan.pethome.basic.util.HttpClientUtils;
import com.donglan.pethome.basic.util.MD5Utils;
import com.donglan.pethome.basic.util.RedisUtil;
import com.donglan.pethome.basic.util.StrUtil;
import com.donglan.pethome.user.constant.UserConstant;
import com.donglan.pethome.user.constant.WechatConstant;
import com.donglan.pethome.user.domain.User;
import com.donglan.pethome.user.domain.WechatUser;
import com.donglan.pethome.user.domain.vo.UserVo;
import com.donglan.pethome.user.mapper.UserMapper;
import com.donglan.pethome.user.mapper.WechatUserMapper;
import com.donglan.pethome.user.service.WechatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @Author: zhangdonghui
 * @Date: 2022/1/21 13:32
 */
@Service
public class WechatServiceImpl implements WechatService {

    @Autowired
    private WechatUserMapper wechatUserMapper;
    @Autowired
    private UserMapper userMapper;


    /*
     * 功能描述 通过授权码获取token
     * @author zhangdonghui
     * @date 2022/1/21 13:32
     * @param code 授权码
     * @return java.util.Map<java.lang.String,java.lang.Object>
     */
    @Override
    public Map<String, Object> handleCallBack(String code) {
        // 获取tokenurl地址
        String tokenUrl = WechatConstant.TOKENURL.replace("APPID", WechatConstant.APPID)
                .replace("SECRET", WechatConstant.SECRET)
                .replace("CODE", code);
        // 使用java程序发送get请求，它就会返回json格式
        String tokenJsonStr = HttpClientUtils.httpGet(tokenUrl);
        // 把json字符串转为json对象
        JSONObject jsonObject = JSONObject.parseObject(tokenJsonStr);

        // 微信用户唯一标志
        String openid = jsonObject.getString("openid");
        // 获取token的值
        String access_token =  jsonObject.getString("access_token");
        // 当且仅当该网站应用已获得该用户的userinfo授权时，才会出现该字段。
        String unionid = (String) jsonObject.get("unionid");

        //通过token获取微信用户数据资源
        String userInfoUrl = WechatConstant.USERINFOURL.replace("ACCESS_TOKEN", access_token)
                .replace("OPENID", openid);
        //获取微信用户基本信息(json字符串)
        String userInfoJsonStr = HttpClientUtils.httpGet(userInfoUrl);
        //把用户信息json字符串转为json对象
        jsonObject = JSONObject.parseObject(userInfoJsonStr);
        System.out.println("获取到的微信用户信息：");
        System.out.println(jsonObject);

        // 通过openid唯一标志在微信用户表中查找是否有对应的数据
        WechatUser wechatUser = wechatUserMapper.loadByOpenid(openid);

        //创建一个map集合，封装数据，传递到前端，前端拿到后端传递的数据，可以判断
        Map<String, Object> map = new HashMap<>();
        // 如果对象为空，就证明，当前用户和微信还没有绑定
        // 通过token把对应的资源查询出来并且放到数据库表中
        if(wechatUser == null){
            WechatUser user = new WechatUser();
            // 用户唯一标识
            user.setOpenid(openid);
            // 昵称
            user.setNickname(jsonObject.getString("nickname"));
            // 性别
            user.setSex(jsonObject.getInteger("sex"));
            // 头像
            user.setHeadimgurl(jsonObject.getString("headimgurl"));
            // 授权之后唯一标志
            user.setUnionid(unionid);
            // 省市
            user.setAddress(jsonObject.getString("province")+" "+jsonObject.getString("city"));
            //把user对象给保存起来
            wechatUserMapper.add(user);
            //跳转到绑定界面，携带openid
            map.put("openid", openid);
            return map;
        }

        // 如果wechatUser不为空，则获取绑定的user对象
        User user = wechatUser.getUser();
        if(user == null){
            //跳转到绑定界面
            map.put("openid", openid);
            return map;
        }

        // 直接登录
        String token = UUID.randomUUID().toString();
        RedisUtil.INSTANCE.set(token,JSONObject.toJSONString(user),30*60);
        // 那么响应给前端，需要响应两个值，也就是我们模拟的JSESSIONID`
        map.put("token", token);
        map.put("loginUser", user);

        return map;
    }

    /*
     * 功能描述 让微信绑定用户
     * @author zhangdonghui
     * @date 2022/1/21 23:24
     * @param userVo 
     * @return java.util.Map<java.lang.String,java.lang.Object>
     */
    @Override
    public Map<String, Object> binder(UserVo userVo) {

        //获取username，方便sql语句查询数据
        String username = userVo.getUsername();
        Map<String,Object> map = new HashMap<>();
        map.put("username",username);
        User user = userMapper.loadByUsernameOrEmailOrPhone(map);
        // 如果用户为空，则注册用户
        if(user == null){
            // 将临时对象的数据转到binderUser，代码优化之后复用user
            user = userVoToUser(userVo);
            // 用户状态为启用
            user.setState(UserConstant.ACTIVATION);
            // 保存用户
            userMapper.add(user);
        } else {
            // 用户不为空
            if(!user.getPassword().equals(MD5Utils.encrypByMd5(userVo.getPassword()+user.getSalt()))){
                throw new RuntimeException("用户已存在，但是密码错误");
            }
        }
        // 保存之后，绑定微信：微信和用户绑定一起（修改t_wxuser表）
        wechatUserMapper.updateByOpenid(user,userVo.getOpenid());
        // 直接登录
        String token = UUID.randomUUID().toString();
        RedisUtil.INSTANCE.set(token,JSONObject.toJSONString(user),30*60);
        // 那么响应给前端，需要响应两个值，也就是我们模拟的JSESSIONID`
        map.put("token", token);
        map.put("loginUser", user);
        map.remove("username");
        return map;
    }

    private User userVoToUser(UserVo userVo) {
        User binderUser = new User();
        binderUser.setUsername(userVo.getUsername());
        binderUser.setSalt(StrUtil.getComplexRandomString(10));
        binderUser.setPassword(MD5Utils.encrypByMd5(userVo.getPassword()+binderUser.getSalt()));
        return binderUser;

    }

}
